package imse.team1.transportationorder.ws;


/**
 * Created by IntelliJ IDEA.
 * User: Evgenia
 * Date: 6/20/12
 * Time: 9:34 PM
 * To change this template use File | Settings | File Templates.
 */

import imse.team1.order.ws.client.OrderStatusUpdateService;
import imse.team1.order.ws.client.OrderStatusUpdateServiceStub;
import imse.team1.transportationorder.googlemapsapi.CachedTransportationOrders;
import imse.team1.transportationorder.googlemapsapi.CalcDistFromOriginToDest;
import imse.team1.transportationorders.data.*;

import java.io.IOException;
import java.rmi.RemoteException;
import java.util.*;

public class TransportationPriceCalculationServiceSkeleton implements TransportationPriceCalculationServiceSkeletonInterface {
    public final static String CACHEFILE = "/settings.properties";
    private static double priceEmpty;
    private static double priceLoaded;
    private static String companyLocation;
    public final static String cacheFileId;
    // order ID and routes
    private static HashMap<String, Route> transportationOrders = new HashMap<String, Route>();

    static {
        try {
            Properties prop = new Properties();
            prop.load(TransportationPriceCalculationServiceSkeleton.class.getResourceAsStream(CACHEFILE));
            priceEmpty = Double.parseDouble(prop.getProperty("priceEmpty"));
            priceLoaded = Double.parseDouble(prop.getProperty("priceLoaded"));
            companyLocation = prop.getProperty("companyLocation");
            cacheFileId = prop.getProperty("cache_file_id");
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    public RoutePrice calcPriceFromWarehousesToRetailers(Route totalRoute) {
        RouteCity[] routes = totalRoute.getRouteCity();
        // calculate total distance and price for the route
        Double totalDistance = 0.0;
        Double totalPrice = 0.0;

        int numbdestinations = routes.length;

        // construct final route
        // Transport Comp, WH1, WH2, ... Retailer, Trans Comp back
        ArrayList<String> deliveryRoute = new ArrayList<String>();
        deliveryRoute.add(companyLocation);
        for (RouteCity route : routes) {
            String locationName = route.getLocationName();
            deliveryRoute.add(locationName);
        }
        deliveryRoute.add(companyLocation);

        for (int i = 0; i < deliveryRoute.size() - 1; i++) {
            Double dist = CalcDistFromOriginToDest.calculateDistanceOrigToDest(deliveryRoute.get(i), deliveryRoute.get(i + 1));
            totalDistance = totalDistance + dist;
            if (i == 0) {
                totalPrice = totalPrice + dist * priceEmpty;
            }
            if (i == (deliveryRoute.size() - 2)) {
                totalPrice = totalPrice + dist * priceEmpty;
            } else {
                totalPrice = totalPrice + dist * priceLoaded;
            }
        }
        RoutePrice routePrice = new RoutePrice();
        routePrice.setPrice(totalPrice);
        TransportationOrderID tordID = new TransportationOrderID();
        String transpOderId = UUID.randomUUID().toString();
        transportationOrders.put(transpOderId, totalRoute);
        tordID.setTransportationOrderID(transpOderId);
        routePrice.setTransportationOrderID(tordID);
        System.out.println("------------> calc price method called with: "+tordID.getTransportationOrderID());
        return routePrice;
    }

    public Order placeTransportationOrder(TransportationOrderID toID) {
        Order order = new Order();
        System.out.println("------------> placeOrder method called with: "+toID.getTransportationOrderID());
        String orderID = toID.getTransportationOrderID();
        boolean orderPlaced = false;
        Iterator it = transportationOrders.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry pairs = (Map.Entry) it.next();
            if (((String) pairs.getKey()).equals(orderID)) {
                // place order and answer order is in delivery
                order.setStatus(Status.PLACED);
                // here will instantiate delivery thread -send transp order ID
                //which after 2 min will call WineProd service
                // to inform that the wine was delivered to retailer

                order.setTransportationOrderID(toID);
                CachedTransportationOrders.placedTranspOrders.put(order.getTransportationOrderID().getTransportationOrderID(), order);
                Thread deliveryThread = new Thread(new Delivery(order.getTransportationOrderID().getTransportationOrderID()));
                deliveryThread.setDaemon(true);
                deliveryThread.start();
                orderPlaced = true;
                break;
            }
        }
        if (!orderPlaced) {
            order.setStatus(Status.REJECTED);
            order.setTransportationOrderID(toID);
        }
        return order;
    }

    class Delivery implements Runnable {
        private String orderid;

        Delivery(String orderid) {
            this.orderid = orderid;
        }

        public void run() {
            try {
                synchronized (CachedTransportationOrders.placedTranspOrders) {
                    Thread.currentThread().sleep(2000L);
                    Order currOrder = CachedTransportationOrders.placedTranspOrders.get(orderid);
                    currOrder.setStatus(Status.DELIVERED);
                    try {
                        System.out.println("------------> Inside super sending thread. Orderid: "+currOrder.getTransportationOrderID().getTransportationOrderID());
                        OrderStatusUpdateService updateStatusReceiverService = new OrderStatusUpdateServiceStub();
                        updateStatusReceiverService.updateTransportationOrderStatus(currOrder);
                    } catch (RemoteException axisFault) {
                        axisFault.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                        throw new RuntimeException(axisFault);
                    }
                    CachedTransportationOrders.placedTranspOrders.remove(orderid);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

}
